package com.gitee.beiding.template_excel;

import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.*;

public final class Renderer {


    private Renderer() {
    }

    /**
     * 使用Map作为数据源进行渲染
     *
     * @param data          被渲染的数据
     * @param templateSheet 模板sheet页
     * @param targetSheet   接收渲染结果的sheet页
     */
    public static void render(Map<String, Object> data, XSSFSheet templateSheet, XSSFSheet targetSheet, RenderContext renderContext) {

        try {

            RenderContext.setCurrent(renderContext);


            //放入目标数据
            Js.putAll(data);

            //复制样式
            PoiUtils.copySheet(templateSheet, targetSheet);

            //处理列宽
            PoiUtils.handleColumnWidth(templateSheet, targetSheet);

            //读取内容
            Map<Integer, Map<Integer, Object>> templateRow = PoiUtils.readSheet(templateSheet);

            //模板展开为实际数据
            Map<Integer, List<Map<Integer, RenderHolder>>> map = templateRowToValueRows(templateRow);

            //复制数据
            //PoiUtils.copySheetDataWithData(srcSheet, targetSheet, map);

            // 复制数据
            TemplateUtils.copySheetDataWithData(templateSheet, targetSheet, map);

        }finally {

            //渲染后重置
            RenderContext.clear();

        }

    }

    /**
     * 使用工作簿渲染生成一个新的工作簿
     *
     * @param data               数据源
     * @param template           模板sheet页
     * @param templateSheetNames 需要被渲染的sheet页名称
     * @return 渲染的结果
     */
    public static XSSFWorkbook render(Map<String, Object> data, XSSFWorkbook template, RenderContext renderContext, String... templateSheetNames) {


        try {
            RenderContext.setCurrent(renderContext);

            Js.putAll(data);


            //复制一份作为输出
            XSSFWorkbook target = null;

            try {
                //可以断言Io异常不会出现
                ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
                template.write(byteArrayOutputStream);
                target = PoiUtils.read(new ByteArrayInputStream(byteArrayOutputStream.toByteArray()));
            } catch (IOException ignore) {
            }

            List<String> list = Arrays.asList(templateSheetNames);

            //遍历所有的sheet页
            for (int i = 0; i < template.getNumberOfSheets(); i++) {
                XSSFSheet srcSheet = template.getSheetAt(i);

                XSSFSheet targetSheet = target.getSheet(srcSheet.getSheetName());

                if (list.size() > 0 && !list.contains(srcSheet.getSheetName())) {
                    continue;
                }

                if (targetSheet == null) {
                    target.createSheet(srcSheet.getSheetName());
                } else {
                    for (int j = 0; j <= targetSheet.getLastRowNum(); j++) {
                        XSSFRow row = targetSheet.getRow(j);
                        if (row != null) {
                            targetSheet.removeRow(row);
                        }
                    }
                }

                //复制样式
                PoiUtils.copySheet(srcSheet, targetSheet);

                //处理列宽
                PoiUtils.handleColumnWidth(srcSheet, targetSheet);

                //读取内容
                Map<Integer, Map<Integer, Object>> templateRow = PoiUtils.readSheet(srcSheet);


                //模板展开为实际数据
                Map<Integer, List<Map<Integer, RenderHolder>>> map = templateRowToValueRows(templateRow);

                //复制数据
                //PoiUtils.copySheetDataWithData(srcSheet, targetSheet, map);

                // 复制数据
                TemplateUtils.copySheetDataWithData(srcSheet, targetSheet, map);

            }
            return target;
        } finally {

            RenderContext.clear();
        }

    }

    private static Map<Integer, List<Map<Integer, RenderHolder>>> templateRowToValueRows(Map<Integer, Map<Integer, Object>> templateRow) {

        //全局索引
        int[] globalIndex = new int[1];

//        globalIndex[0] = 0;

        Map<Integer, List<Map<Integer, RenderHolder>>> map = new HashMap<>();

        //遍历模板中的所有行
        templateRow.forEach((rowNumber, row) -> {

            //最大数
            Map<String, Integer> max = new LinkedHashMap<>();

            //所有的值
            Map<Integer, TemplateCell> values = new HashMap<>();

            //遍历一行中的所有单元格
            row.forEach((colNumber, col) -> {

                //解析结果
                TemplateCell parse = TemplateCell.parse(col);

                //执行得到结果
                parse.exe();

                values.put(colNumber, parse);

                //获取索引
                Map<String, Integer> indexMax = parse.getIndexMax();

                //找到索引最大值
                if (indexMax != null) {
                    indexMax.forEach((name, maxValue) -> {
                        Integer integer = max.get(name);
                        if (integer == null || maxValue > integer) {
                            max.put(name, maxValue);
                        }
                    });
                }

            });


            int index = 0;

            if (max.size() > 0) {

                //创建自增数字
                AutoIncrementNumber autoIncrementNumber = new AutoIncrementNumber();

                //按照最大值初始化
                autoIncrementNumber.init(max);

                //全部数据  每个Map一行key为列
                List<Map<Integer, RenderHolder>> list = new ArrayList<>();

                //自增
                out:
                while (autoIncrementNumber.autoIncrement()) {//循环自增

                    Map<String, Integer> nvs = autoIncrementNumber.getValues();

                    //将自增数放入
                    Js.putAll(nvs);

                    //可在js中使用的索引
                    Js.set("_index", index);

                    Map<Integer, RenderHolder> line = new HashMap<>();

                    //全局索引
                    Js.set("_globalIndex", globalIndex[0]);

                    //如果有一个元素是无效的就直接返回
                    for (Integer colValue : values.keySet()) {

                        //活动列
                        TemplateCell tc = values.get(colValue);
                        try {

                            Js.set("_col", colValue);

                            //
                            line.put(colValue, tc.get(autoIncrementNumber.getValues()));
                        } catch (InvalidIndexException e) {

                            //    System.out.println("无效索引:" + autoIncrementNumber.getValues());

                            continue out;
                        }
                    }


                    if (line.size() > 0) {
                        index++;
                        globalIndex[0]++;
                        list.add(line);
                    }
                }

                if (list.size() > 0) {
                    map.put(rowNumber, list);
                }

            } else {
                List<Map<Integer, RenderHolder>> list = new ArrayList<>();
                Map<Integer, RenderHolder> line = new HashMap<>();
                values.forEach((colValue, tc) -> {
                    line.put(colValue, tc.get(Collections.emptyMap()));
                });
                if (line.size() > 0) {
                    list.add(line);
                    map.put(rowNumber, list);
                }
            }

            try {

                //清空缓存,防止oom
                Js.call("_clearCache");
            } catch (Exception e) {
                e.printStackTrace();
            }

        });


        return map;
    }


    //测试


}

